/*
 * HackSQL
 * Copyright (C) 2008-2009
 *
 * Authors: Felipe Nascimento Silva Pena
 *		  Henrique Montenegro Decaria
 *		  Higor Eurípedes Pimentel Fernandes de Araújo
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 * 
 * $Id$
 */


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#ifdef HAVE_CONFIG_H
# include <config.h>
#endif

#ifdef WIN32
# include "../win32/win32.h"
#else
# include <sys/types.h>
# include <sys/socket.h>
# include <arpa/inet.h>
# include <netdb.h>
#endif

#include <hacksql/hacksql.h>
#include <hacksql/libhacksql.h>

#include "utils.h"

#define HACKSQL_BUFFER 255

static char *username = HACKSQL_DEFAULT_USERNAME;
static char *password = NULL;
static char *hostname = HACKSQL_DEFAULT_SERVER;
static char *hostport = HACKSQL_DEFAULT_PORT;
static char *database = NULL;

static int my_sock;
static char *query_error;

void hacksql_init(void)
{
}

void hacksql_end(void)
{
	hacksql_disconnect();
}

void hacksql_server_shutdown(void)
{
	
}

void hacksql_server_restart(void)
{
}

int hacksql_connect(char *host, char *port, char *user, char *pass)
{
	struct addrinfo info;
	struct addrinfo *server;
	char buf[4096];

	memset(&info, 0, sizeof(info));
	info.ai_family = AF_INET;	/* IPv4 for now */
	info.ai_socktype = SOCK_STREAM;
	
	host = (!host ? HACKSQL_DEFAULT_SERVER   : host);
	port = (!port ? HACKSQL_DEFAULT_PORT     : port);
	user = (!user ? HACKSQL_DEFAULT_USERNAME : user);
	/* pass = (!pass ? HACKSQL_DEFAULT_PASSWORD : pass); */

	if (getaddrinfo(host, port, &info, &server) != 0) {
		printf(_("Error on getaddrinfo\n"));
		return -1;
	}

	my_sock = socket(server->ai_family, server->ai_socktype, server->ai_protocol);

	if (my_sock < 0) {
		printf(_("Error creating socket\n"));
		return -1;
	}

	if (connect(my_sock, server->ai_addr, server->ai_addrlen) == -1) {
		printf(_("Error connecting\n"));
		return -1;
	}

	freeaddrinfo(server);

	/* Determine some handshake here to authenticate the user */

	sprintf(buf, "USER %s", user);
	send(my_sock, buf, strlen(buf), 0);

	hostname = host;
	hostport = port;
	username = user;
	password = pass;
	
	return 0;
}

void hacksql_disconnect(void)
{
	const char *buf = "close_hs_connection";
	
	if (my_sock >= 0) {
		send(my_sock, buf, strlen(buf), 0);
		close(my_sock);
	}
}

/* 
 * This function should ping the server, and reconnect if the connection
 * has expired.
 */
int hacksql_ping(void)
{
	/* TODO: rewrite everything here. */
	int sockfd, numbytes;
	char buf[HACKSQL_MAX_RECV_DATA];
	struct addrinfo hints, *servinfo, *p;
	int rv;
	char s[INET_ADDRSTRLEN];

	memset(&hints, 0, sizeof hints);
	hints.ai_family = AF_UNSPEC;
	hints.ai_socktype = SOCK_STREAM;

	if ((rv = getaddrinfo("localhost", "4225", &hints, &servinfo)) != 0) {
		return -1;
	}

	/* loop through all the results and connect to the first we can */
	for (p = servinfo; p != NULL; p = p->ai_next) {
		if ((sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1) {
			continue;
		}

		if (connect(sockfd, p->ai_addr, p->ai_addrlen) == -1) {
			close(sockfd);
			continue;
		}
		break;
	}

	if (p == NULL) {
		printf("client: failed to connect\n");
		return -1;
	}

	inet_ntop(p->ai_family, get_in_addr((struct sockaddr *) p->ai_addr), s, sizeof s);
	printf("client: connecting to %s\n", s);

	freeaddrinfo(servinfo);	/* all done with this structure */

	if ((numbytes = recv(sockfd, buf, HACKSQL_MAX_RECV_DATA - 1, 0)) == -1) {
		printf("recv");
		return -1;
	}

	buf[numbytes] = '\0';

	printf("client: received '%s'\n", buf);

	close(sockfd);
	
	return 0;
}

int hacksql_select_db(char *dbname)
{
	if (!dbname) {
		return -1;
	}
	database = dbname;
	
	return 0;
}

int hacksql_query(char *query)
{
	char buf[HACKSQL_BUFFER+1];

	if (my_sock >= 0) {
		send(my_sock, query, strlen(query)+1, 0);
	}
	
	recv(my_sock, buf, HACKSQL_BUFFER, 0);
	
	if (strncmp(buf, "Success", sizeof("Success")-1) == 0) {
		return SUCCESS;
	}
	
	query_error = strdup(buf);	
		
	return FAILURE;
}

char *hacksql_error(void)
{
	return query_error;
}
